/**
 * Copyright (c) 2006-2012, JGraph Ltd
 */
/**
 * 为给定的编辑器UI构造一个新的菜单管理器。
 * 菜单管理器负责创建和管理所有菜单项，包括字体、格式、对齐等功能。
 *
 * @param {Object} editorUi - 菜单管理器所属的编辑器UI实例
 */
Menus = function (editorUi) {
    // 存储编辑器UI实例的引用，用于访问图形编辑器和相关功能
    this.editorUi = editorUi;
    // 存储所有已注册菜单的映射表，键为菜单名称，值为菜单对象
    this.menus = new Object();
    // 初始化所有菜单项和功能
    this.init();

    // 预加载选中标记图片，提升用户体验
    if (!mxClient.IS_SVG) {
        new Image().src = this.checkmarkImage;
    }
};

/**
 * 设置默认的字体族名称。
 * 用于在字体菜单中显示的默认字体选项。默认为'Helvetica'。
 */
Menus.prototype.defaultFont = 'Helvetica';

/**
 * 设置默认的字体大小。
 * 用于字体大小选择器的默认值，以像素为单位。默认为'12'。
 */
Menus.prototype.defaultFontSize = '12';

/**
 * 设置默认的菜单项列表。
 * 定义了编辑器菜单栏中显示的主要菜单项顺序。默认为['file', 'edit', 'view', 'arrange', 'extras', 'help']。
 */
Menus.prototype.defaultMenuItems = ['file', 'edit', 'view', 'arrange', 'extras', 'help'];

/**
 * 设置默认的字体列表。
 * 提供给用户在字体菜单中选择的预定义字体选项数组。
 */
Menus.prototype.defaultFonts = ['Helvetica', 'Verdana', 'Times New Roman', 'Garamond', 'Comic Sans MS',
    'Courier New', 'Georgia', 'Lucida Console', 'Tahoma'
];

/**
 * 初始化菜单管理器的所有菜单项和功能。
 * 该方法设置了字体、格式、对齐、视图等各种菜单的功能和回调函数。
 */
Menus.prototype.init = function () {
    // 获取图形编辑器的引用，用于操作图形元素
    var graph = this.editorUi.editor.graph;
    // 创建绑定函数，用于检查图形是否启用状态
    var isGraphEnabled = mxUtils.bind(graph, graph.isEnabled);

    // 存储用户自定义的字体列表
    this.customFonts = [];
    // 存储用户自定义的字体大小列表
    this.customFontSizes = [];

    // 设置字体族菜单，提供字体选择功能
    this.put('fontFamily', new Menu(mxUtils.bind(this, function (menu, parent) {
        // 定义添加字体菜单项的内部函数
        var addItem = mxUtils.bind(this, function (fontname) {
            // 为指定的字体创建样式改变菜单项
            var tr = this.styleChange(menu, fontname, [mxConstants.STYLE_FONTFAMILY], [fontname], null, parent, function () {
                // 在内容编辑模式下使用document命令设置字体
                document.execCommand('fontname', false, fontname);
            }, function () {
                // 更新选中元素的标签样式，移除face属性并重置字体样式
                graph.updateLabelElements(graph.getSelectionCells(), function (elt) {
                    elt.removeAttribute('face');
                    elt.style.fontFamily = null;

                    // 如果是PRE元素，替换为DIV元素
                    if (elt.nodeName == 'PRE') {
                        graph.replaceElement(elt, 'div');
                    }
                });
            });
            // 设置菜单项的字体样式预览
            tr.firstChild.nextSibling.style.fontFamily = fontname;
        });

        // 为所有默认字体添加菜单项
        for (var i = 0; i < this.defaultFonts.length; i++) {
            addItem(this.defaultFonts[i]);
        }

        // 添加分隔符
        menu.addSeparator(parent);

        // 如果有自定义字体，添加它们到菜单
        if (this.customFonts.length > 0) {
            for (var i = 0; i < this.customFonts.length; i++) {
                addItem(this.customFonts[i]);
            }

            menu.addSeparator(parent);

            // 添加重置自定义字体的选项
            menu.addItem(mxResources.get('reset'), null, mxUtils.bind(this, function () {
                this.customFonts = [];
                this.editorUi.fireEvent(new mxEventObject('customFontsChanged'));
            }), parent);

            menu.addSeparator(parent);
        }

        // 添加自定义字体输入选项
        this.promptChange(menu, mxResources.get('custom') + '...', '', mxConstants.DEFAULT_FONTFAMILY, mxConstants.STYLE_FONTFAMILY, parent, true, mxUtils.bind(this, function (newValue) {
            // 如果自定义字体列表中不存在该字体，则添加它
            if (mxUtils.indexOf(this.customFonts, newValue) < 0) {
                this.customFonts.push(newValue);
                this.editorUi.fireEvent(new mxEventObject('customFontsChanged'));
            }
        }));
    })));
    // 设置格式块菜单，提供文本格式化选项（如标题、段落等）
    this.put('formatBlock', new Menu(mxUtils.bind(this, function (menu, parent) {
        // 定义添加格式块菜单项的内部函数
        function addItem(label, tag) {
            return menu.addItem(label, null, mxUtils.bind(this, function () {
                // TODO: 检查是否可见
                if (graph.cellEditor.textarea != null) {
                    // 聚焦文本编辑器并应用格式块命令
                    graph.cellEditor.textarea.focus();
                    document.execCommand('formatBlock', false, '<' + tag + '>');
                }
            }), parent);
        };

        // 添加普通段落选项
        addItem(mxResources.get('normal'), 'p');

        // 添加各级标题选项，并设置预览样式
        addItem('', 'h1').firstChild.nextSibling.innerHTML = '<h1 style="margin:0px;">' + mxResources.get('heading') + ' 1</h1>';
        addItem('', 'h2').firstChild.nextSibling.innerHTML = '<h2 style="margin:0px;">' + mxResources.get('heading') + ' 2</h2>';
        addItem('', 'h3').firstChild.nextSibling.innerHTML = '<h3 style="margin:0px;">' + mxResources.get('heading') + ' 3</h3>';
        addItem('', 'h4').firstChild.nextSibling.innerHTML = '<h4 style="margin:0px;">' + mxResources.get('heading') + ' 4</h4>';
        addItem('', 'h5').firstChild.nextSibling.innerHTML = '<h5 style="margin:0px;">' + mxResources.get('heading') + ' 5</h5>';
        addItem('', 'h6').firstChild.nextSibling.innerHTML = '<h6 style="margin:0px;">' + mxResources.get('heading') + ' 6</h6>';

        // 添加预格式化和引用块选项
        addItem('', 'pre').firstChild.nextSibling.innerHTML = '<pre style="margin:0px;">' + mxResources.get('formatted') + '</pre>';
        addItem('', 'blockquote').firstChild.nextSibling.innerHTML = '<blockquote style="margin-top:0px;margin-bottom:0px;">' + mxResources.get('blockquote') + '</blockquote>';
    })));
    // 设置字体大小菜单，提供各种字体大小选项
    this.put('fontSize', new Menu(mxUtils.bind(this, function (menu, parent) {
        // 定义可用的字体大小数组
        var sizes = [6, 8, 9, 10, 11, 12, 14, 18, 24, 36, 48, 72];

        // 定义添加字体大小菜单项的内部函数
        var addItem = mxUtils.bind(this, function (fontsize) {
            this.styleChange(menu, fontsize, [mxConstants.STYLE_FONTSIZE], [fontsize], null, parent, function () {
                if (graph.cellEditor.textarea != null) {
                    // 创建一个size为3的font元素作为临时占位符
                    document.execCommand('fontSize', false, '3');

                    // 修改第一个size为3的font元素的CSS字体大小
                    // 希望这就是上面刚创建的元素。后需改进：使用getElementsByTagName的先前结果检查新元素
                    var elts = graph.cellEditor.textarea.getElementsByTagName('font');

                    for (var i = 0; i < elts.length; i++) {
                        if (elts[i].getAttribute('size') == '3') {
                            elts[i].removeAttribute('size');
                            elts[i].style.fontSize = fontsize + 'px';

                            break;
                        }
                    }
                }
            });
        });

        // 为所有预定义字体大小添加菜单项
        for (var i = 0; i < sizes.length; i++) {
            addItem(sizes[i]);
        }

        menu.addSeparator(parent);

        // 如果有自定义字体大小，添加它们到菜单
        if (this.customFontSizes.length > 0) {
            for (var i = 0; i < this.customFontSizes.length; i++) {
                addItem(this.customFontSizes[i]);
            }

            menu.addSeparator(parent);

            // 添加重置自定义字体大小的选项
            menu.addItem(mxResources.get('reset'), null, mxUtils.bind(this, function () {
                this.customFontSizes = [];
            }), parent);

            menu.addSeparator(parent);
        }

        // 添加自定义字体大小输入选项
        this.promptChange(menu, mxResources.get('custom') + '...', '(pt)', '12', mxConstants.STYLE_FONTSIZE, parent, true, mxUtils.bind(this, function (newValue) {
            this.customFontSizes.push(newValue);
        }));
    })));
    // 设置方向菜单，提供图形翻转和旋转功能
    this.put('direction', new Menu(mxUtils.bind(this, function (menu, parent) {
        // 添加水平翻转选项
        menu.addItem(mxResources.get('flipH'), null, function () {
            graph.toggleCellStyles(mxConstants.STYLE_FLIPH, false);
        }, parent);
        // 添加垂直翻转选项
        menu.addItem(mxResources.get('flipV'), null, function () {
            graph.toggleCellStyles(mxConstants.STYLE_FLIPV, false);
        }, parent);
        // 添加分隔符和旋转选项
        this.addMenuItems(menu, ['-', 'rotation'], parent);
    })));
    // 设置对齐菜单，提供各种对齐选项
    this.put('align', new Menu(mxUtils.bind(this, function (menu, parent) {
        // 水平对齐选项
        menu.addItem(mxResources.get('leftAlign'), null, function () {
            graph.alignCells(mxConstants.ALIGN_LEFT);
        }, parent);
        menu.addItem(mxResources.get('center'), null, function () {
            graph.alignCells(mxConstants.ALIGN_CENTER);
        }, parent);
        menu.addItem(mxResources.get('rightAlign'), null, function () {
            graph.alignCells(mxConstants.ALIGN_RIGHT);
        }, parent);
        menu.addSeparator(parent);
        // 垂直对齐选项
        menu.addItem(mxResources.get('topAlign'), null, function () {
            graph.alignCells(mxConstants.ALIGN_TOP);
        }, parent);
        menu.addItem(mxResources.get('middle'), null, function () {
            graph.alignCells(mxConstants.ALIGN_MIDDLE);
        }, parent);
        menu.addItem(mxResources.get('bottomAlign'), null, function () {
            graph.alignCells(mxConstants.ALIGN_BOTTOM);
        }, parent);
    })));
    // 设置分布菜单，提供元素分布功能
    this.put('distribute', new Menu(mxUtils.bind(this, function (menu, parent) {
        // 水平分布选项
        menu.addItem(mxResources.get('horizontal'), null, function () {
            graph.distributeCells(true);
        }, parent);
        // 垂直分布选项
        menu.addItem(mxResources.get('vertical'), null, function () {
            graph.distributeCells(false);
        }, parent);
    })));
    // 设置布局菜单，提供树形布局和间距调整功能
    this.put('layout', new Menu(mxUtils.bind(this, function (menu, parent) {
        var promptSpacing = mxUtils.bind(this, function (defaultValue, fn) {
            var dlg = new FilenameDialog(this.editorUi, defaultValue, mxResources.get('apply'), function (newValue) {
                fn(parseFloat(newValue));
            }, mxResources.get('spacing'));
            this.editorUi.showDialog(dlg.container, 300, 80, true, true);
            dlg.init();
        });

        function excuteTreeLayout(horizontal) {
            var action = this.editorUi.actions.get('treeLayout');

            action.funct(horizontal)

            this.get('layout').horizontal = horizontal;
            this.editorUi.setToolbarValue('treeLayoutHorizon', horizontal);
        }

        menu.addItem(mxResources.get('horizontalTree'), null, excuteTreeLayout.bind(this, true), parent);
        menu.addItem(mxResources.get('verticalTree'), null, excuteTreeLayout.bind(this, false), parent);
    })));
    // 设置导航菜单，提供导航控制和展开折叠功能
    this.put('navigation', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['home', '-', 'exitGroup', 'enterGroup', '-', 'expand', 'collapse', '-', 'collapsible'], parent);
    })));
    // 设置排列菜单，提供图层、对齐、分布、导航和布局功能
    this.put('arrange', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['toFront', 'toBack', '-'], parent);
        this.addSubmenu('direction', menu, parent);
        this.addMenuItems(menu, ['turn', '-'], parent);
        this.addSubmenu('align', menu, parent);
        this.addSubmenu('distribute', menu, parent);
        menu.addSeparator(parent);
        this.addSubmenu('navigation', menu, parent);
        this.addSubmenu('insert', menu, parent);
        this.addSubmenu('layout', menu, parent);
        this.addMenuItems(menu, ['-', 'group', 'ungroup', 'removeFromGroup', '-', 'clearWaypoints', 'autosize'], parent);
    }))).isEnabled = isGraphEnabled;
    // 设置插入菜单，提供链接和图片插入功能
    this.put('insert', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['insertLink', 'insertImage'], parent);
    })));
    // 设置视图菜单，提供面板、缩放、网格、指南等视图控制功能
    this.put('view', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ((this.editorUi.format != null) ? ['formatPanel'] : []).concat(['outline', 'layers', '-', 'pageView', 'pageScale', '-', 'scrollbars', 'tooltips', '-',
            'grid', 'guides', '-', 'connectionArrows', 'connectionPoints', '-',
            'resetView', 'zoomIn', 'zoomOut'
        ], parent));
    })));
    // 两个特殊的下拉菜单，仅在工具栏中使用
    this.put('viewPanels', new Menu(mxUtils.bind(this, function (menu, parent) {
        if (this.editorUi.format != null) {
            this.addMenuItems(menu, ['formatPanel'], parent);
        }

        this.addMenuItems(menu, ['outline', 'layers'], parent);
    })));
    // 设置缩放视图菜单，提供各种预设缩放比例和适应窗口选项
    this.put('viewZoom', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['resetView', '-'], parent);
        var scales = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4];

        for (var i = 0; i < scales.length; i++) {
            (function (scale) {
                menu.addItem((scale * 100) + '%', null, function () {
                    graph.zoomTo(scale);
                }, parent);
            })(scales[i]);
        }

        this.addMenuItems(menu, ['-', 'fitWindow', 'fitPageWidth', 'fitPage', 'fitTwoPages', '-', 'customZoom'], parent);
    })));
    // 设置文件菜单，提供新建、打开、保存、导入导出等文件操作功能
    this.put('file', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['new', 'open', '-', 'save', 'saveAs', '-', 'import', 'export', '-', 'pageSetup', 'print'], parent);
    })));
    // 设置编辑菜单，提供撤销重做、剪切复制粘贴、选择等编辑操作功能
    this.put('edit', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['editData', '-', 'undo', 'redo', '-', 'cut', 'copy', 'paste', 'delete', 'deleteFromModel', '-', 'duplicate',
            'editTooltip', '-', 'editStyle', '-', 'edit', '-', 'editLink', 'openLink', '-',
            'selectVertices', 'selectEdges', 'selectAll', 'selectNone', '-', 'lockUnlock'
        ]);
    })));
    // 设置附加功能菜单，提供复制连接、折叠展开和编辑图表功能
    this.put('extras', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['copyConnect', 'collapseExpand', '-', 'editDiagram']);
    })));
    // 设置帮助菜单，提供帮助文档和关于信息
    this.put('help', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.addMenuItems(menu, ['help', '-', 'about']);
    })));

    /***********自定义toolbar相关***************/
    // 对齐方式
    this.put('alignType', new Menu(mxUtils.bind(this, function (menu, parent) {
        const alignMap = {
            [mxConstants.ALIGN_LEFT]: '左对齐',
            [mxConstants.ALIGN_RIGHT]: '右对齐',
            [mxConstants.ALIGN_TOP]: '顶部对齐',
            [mxConstants.ALIGN_BOTTOM]: '底部对齐',
            [mxConstants.ALIGN_CENTER]: '垂直对齐',
            [mxConstants.ALIGN_MIDDLE]: '水平对齐',
        }
        Object.keys(alignMap).forEach((key) => {
            const label = alignMap[key]
            const elt = menu.addItem(alignMap[key], null, mxUtils.bind(this, function () {
                graph.alignCells(key);
            }), parent);
            $(elt).children().eq(1).prepend($(`<img src="img/toolbar/${label}.svg" style="margin: 0 5px 0 0;width: 16px;vertical-align: text-bottom;">`))
        })
        const geoMap = ['等大小', '等高', '等宽']
        geoMap.forEach(item => {
            const elt = menu.addItem(item, null, mxUtils.bind(this, function () {
                graph.getModel().beginUpdate();
                try {
                    const cells = graph.getSelectionCells().filter(function (c) {
                        return graph.getModel().isVertex(c)
                    })
                    const firstGeo = graph.getCellGeometry(cells[0])

                    cells.forEach(cell => {
                        if (graph.getModel().isVertex(cell)) {
                            let geo = graph.getCellGeometry(cell)

                            if (geo != null) {
                                geo = geo.clone();

                                if (item !== '等高') {
                                    geo.width = firstGeo.width
                                }
                                if (item !== '等宽') {
                                    geo.height = firstGeo.height
                                }
                                graph.model.setGeometry(cell, geo)
                                graph.constrainChildCells(cell);
                            }
                        }
                    })
                } finally {
                    graph.getModel().endUpdate();
                }

            }), parent);
            $(elt).children().eq(1).prepend($(`<img src="img/toolbar/${item}.svg" style="margin: 0 5px 0 0;width: 16px;vertical-align: text-bottom;">`))
        })
        const distributeMap = ['水平等间距', '垂直等间距']
        distributeMap.forEach(item => {
            const elt = menu.addItem(item, null, mxUtils.bind(this, function () {
                graph.distributeCells(item === '水平等间距');
            }), parent);
            $(elt).children().eq(1).prepend($(`<img src="img/toolbar/${item}.svg" style="margin: 0 5px 0 0;width: 16px;vertical-align: text-bottom;">`))
        })
    })));

    const changeCellsStyle = mxUtils.bind(this, function (cells, style) {
        const keys = []
        const values = []
        style.split(';').forEach(token => {
            const [key, value] = token.split('=')
            if (value) {
                keys.push(key)
                values.push(value)
            }
        })
        graph.model.beginUpdate();
        try {
            keys.forEach((key, index) => {
                graph.setCellStyles(key, values[index], cells)
            })
            this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', keys, 'values', values, 'cells', cells));
        } finally {
            graph.model.endUpdate();
        }
    })


    // 线段样式
    this.put('lineType', new Menu(mxUtils.bind(this, function (menu, parent) {
        const lineTypes = [{
                solid: '0',
                dashPattern: '0',
                name: 'solid'
            },
            {
                solid: '1',
                dashPattern: '10 4',
                name: 'dashed-6'
            },
            {
                solid: '1',
                dashPattern: '5 2',
                name: 'dashed-5'
            },
            {
                solid: '1',
                dashPattern: '2 1',
                name: 'dashed-4'
            },
            {
                solid: '1',
                dashPattern: '2 2 9 2',
                name: 'dashed-1'
            },
            {
                solid: '1',
                dashPattern: '8 3 2 3 2 3',
                name: 'dashed-3'
            }, // no
            {
                solid: '1',
                dashPattern: '4 4 16 4',
                name: 'dashed-2'
            },
            {
                solid: '1',
                dashPattern: '1 1',
                name: 'dashed-3'
            },
        ]
        lineTypes.forEach(mxUtils.bind(this, function (item, index) {
            const elt = menu.addItem('', `img/toolbar/线段样式${index + 1}.svg`, mxUtils.bind(this, function () {
                graph.stopEditing(false);
                graph.model.beginUpdate();
                try {
                    const cells = graph.getSelectionCells().filter(function (c) {
                        return c.isEdge()
                    })

                    changeCellsStyle(cells.filter(function (c) {
                        return c.style.includes('strokeColor=none')
                    }), `strokeColor=#000000;`)
                    changeCellsStyle(cells, `dashed=${item.solid};dashPattern=${item.dashPattern}`)
                } finally {
                    graph.model.endUpdate();
                }
            }), parent);

            $(elt)
                .find('.mxPopupMenuIcon')
                // .css('background-color', 'unset')
                .css('padding', '3px 6px')
                .find('img')
                .addClass('geIcon')
                .css('display', 'block')
                .css('height', '16px');
        }))
    })))

    // 设置箭头类型菜单，提供各种箭头样式选择
    this.put('arrowType', new Menu(mxUtils.bind(this, function (menu, parent) {
        const noneArrow = ['startArrow=none;endArrow=none;']
        const classicArrow = ['startArrow=none;endArrow=classic;', 'startArrow=classic;endArrow=none;', 'startArrow=classic;endArrow=classic;'].map(i => i + 'startFill=none;endFill=none;')
        const blockArrow = ['startArrow=none;endArrow=block;', 'startArrow=block;endArrow=none;', 'startArrow=block;endArrow=block;'].map(i => i + 'startFill=none;endFill=none;')
        const blockFillArrow = ['startArrow=none;endArrow=block;endFill=0;startFill=none;', 'startArrow=block;endArrow=none;startFill=0;endFill=none;', 'startArrow=block;endArrow=block;endFill=0;startFill=0;']
        noneArrow.concat(classicArrow).concat(blockArrow).concat(blockFillArrow).forEach((style, index) => {
            const elt = menu.addItem('', `img/toolbar/箭头类型${index + 1}.svg`, mxUtils.bind(this, function () {
                changeCellsStyle(graph.getSelectionCells().filter(function (c) {
                    return c.isEdge()
                }), style);
            }), parent)
            $(elt)
                .find('.mxPopupMenuIcon')
                // .css('background-color', 'unset')
                .css('padding', '3px 6px')
                .find('img')
                .addClass('geIcon')
                .css('display', 'block')
                .css('height', '16px');
        })
    })))

    // 线样式
    this.put('edgeStyle', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], [null, null, null], 'geIcon geSprite geSprite-straight', parent, true).setAttribute('title', mxResources.get('straight'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', null, null], 'geIcon geSprite geSprite-orthogonal', parent, true).setAttribute('title', mxResources.get('orthogonal'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalelbow', parent, true).setAttribute('title', mxResources.get('simple'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalelbow', parent, true).setAttribute('title', mxResources.get('simple'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalisometric', parent, true).setAttribute('title', mxResources.get('isometric'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalisometric', parent, true).setAttribute('title', mxResources.get('isometric'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', '1', null], 'geIcon geSprite geSprite-curved', parent, true).setAttribute('title', mxResources.get('curved'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['entityRelationEdgeStyle', null, null], 'geIcon geSprite geSprite-entity', parent, true).setAttribute('title', mxResources.get('entityRelation'));
    })))

    // 线条形状
    this.put('edgeShape', new Menu(mxUtils.bind(this, function (menu, parent) {
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], [null, null], 'geIcon geSprite geSprite-connection', parent, true).setAttribute('title', mxResources.get('line'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], ['link', null], 'geIcon geSprite geSprite-linkedge', parent, true).setAttribute('title', mxResources.get('link'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], ['flexArrow', null], 'geIcon geSprite geSprite-arrow', parent, true).setAttribute('title', mxResources.get('arrow'));
        this.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], ['arrow', null], 'geIcon geSprite geSprite-simplearrow', parent, true).setAttribute('title', mxResources.get('simpleArrow'));
    })))
};

/**
 * 将指定的菜单添加到菜单管理器的菜单映射表中。
 * @param {string} name - 菜单的唯一标识符名称
 * @param {Menu} menu - 要添加的菜单对象
 * @returns {Menu} 返回添加的菜单对象，便于链式调用
 */
Menus.prototype.put = function (name, menu) {
    this.menus[name] = menu;

    return menu;
};

/**
 * 根据名称获取已注册的菜单对象。
 * @param {string} name - 要获取的菜单的标识符名称
 * @returns {Menu} 返回对应的菜单对象，如果不存在则返回undefined
 */
Menus.prototype.get = function (name) {
    return this.menus[name];
};

/**
 * 向指定的菜单添加子菜单项。
 * @param {string} name - 子菜单的名称标识符
 * @param {Menu} menu - 父菜单对象
 * @param {HTMLElement} parent - 父菜单的DOM容器元素
 * @param {string} label - 子菜单的显示标签，如果未提供则使用资源中的默认标签
 */
Menus.prototype.addSubmenu = function (name, menu, parent, label) {
    // 获取指定名称的菜单项
    var entry = this.get(name);

    if (entry != null) {
        // 检查菜单项是否启用
        var enabled = entry.isEnabled();

        // 如果菜单允许显示禁用项或菜单项已启用，则添加子菜单
        if (menu.showDisabled || enabled) {
            var submenu = menu.addItem(label || mxResources.get(name), null, null, parent, null, enabled);
            this.addMenu(name, menu, submenu);
        }
    }
};

/**
 * 向指定的弹出菜单添加子菜单。
 * @param {string} name - 要添加的菜单名称
 * @param {Menu} popupMenu - 弹出菜单对象
 * @param {HTMLElement} parent - 父菜单项的DOM元素
 */
Menus.prototype.addMenu = function (name, popupMenu, parent) {
    // 获取指定名称的菜单
    var menu = this.get(name);

    // 如果菜单存在且满足显示条件，则执行菜单
    if (menu != null && (popupMenu.showDisabled || menu.isEnabled())) {
        this.get(name).execute(popupMenu, parent);
    }
};

/**
 * 为指定的菜单添加插入表格单元格的菜单项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {HTMLElement} parent - 父菜单容器元素
 */
Menus.prototype.addInsertTableCellItem = function (menu, parent) {
    var graph = this.editorUi.editor.graph;

    this.addInsertTableItem(menu, mxUtils.bind(this, function (evt, rows, cols) {
        var table = (mxEvent.isControlDown(evt) || mxEvent.isMetaDown(evt)) ?
            graph.createCrossFunctionalSwimlane(rows, cols) :
            graph.createTable(rows, cols, null, null,
                (mxEvent.isShiftDown(evt)) ? 'Table' : null);
        var pt = (mxEvent.isAltDown(evt)) ? graph.getFreeInsertPoint() :
            graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry([table], true));
        var select = graph.importCells([table], pt.x, pt.y);

        if (select != null && select.length > 0) {
            graph.scrollCellToVisible(select[0]);
            graph.setSelectionCells(select);
        }
    }), parent);
};

/**
 * 为指定的菜单添加插入表格的菜单项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {Function} insertFn - 插入表格的函数，接受事件、行数和列数参数
 * @param {HTMLElement} parent - 父菜单容器元素
 */
Menus.prototype.addInsertTableItem = function (menu, insertFn, parent) {
    insertFn = (insertFn != null) ? insertFn : mxUtils.bind(this, function (evt, rows, cols) {
        var graph = this.editorUi.editor.graph;
        var td = graph.getParentByName(mxEvent.getSource(evt), 'TD');

        if (td != null && graph.cellEditor.textarea != null) {
            var row2 = graph.getParentByName(td, 'TR');

            // 为了找到新的链接，我们首先创建所有现有链接的列表
            // 稍后重构：与下面查找插入图片的代码重复使用
            var tmp = graph.cellEditor.textarea.getElementsByTagName('table');
            var oldTables = [];

            for (var i = 0; i < tmp.length; i++) {
                oldTables.push(tmp[i]);
            }

            // 使用insertHTML可以找到新的表格，但IE不支持该方法
            graph.container.focus();
            graph.pasteHtmlAtCaret(createTable(rows, cols));

            // 将光标移动到第一个表格单元格
            var newTables = graph.cellEditor.textarea.getElementsByTagName('table');

            if (newTables.length == oldTables.length + 1) {
                // 为了支持附加的表格，使用逆序
                for (var i = newTables.length - 1; i >= 0; i--) {
                    if (i == 0 || newTables[i] != oldTables[i - 1]) {
                        graph.selectNode(newTables[i].rows[0].cells[0]);
                        break;
                    }
                }
            }
        }
    });

    // 已知问题：在IE8标准模式和怪异模式下无法工作
    var graph = this.editorUi.editor.graph;
    var row2 = null;
    var td = null;

    function createTable(rows, cols) {
        var html = ['<table>'];

        for (var i = 0; i < rows; i++) {
            html.push('<tr>');

            for (var j = 0; j < cols; j++) {
                html.push('<td><br></td>');
            }

            html.push('</tr>');
        }

        html.push('</table>');

        return html.join('');
    };

    // 显示表格尺寸对话框
    var elt2 = menu.addItem('', null, null, parent, null, null, null, true);

    function createPicker(rows, cols) {
        var table2 = document.createElement('table');
        table2.setAttribute('border', '1');
        table2.style.borderCollapse = 'collapse';
        table2.style.borderStyle = 'solid';
        table2.setAttribute('cellPadding', '8');

        for (var i = 0; i < rows; i++) {
            var row = table2.insertRow(i);

            for (var j = 0; j < cols; j++) {
                var cell = row.insertCell(-1);
            }
        }

        return table2;
    };

    function extendPicker(picker, rows, cols) {
        for (var i = picker.rows.length; i < rows; i++) {
            var row = picker.insertRow(i);

            for (var j = 0; j < picker.rows[0].cells.length; j++) {
                var cell = row.insertCell(-1);
            }
        }

        for (var i = 0; i < picker.rows.length; i++) {
            var row = picker.rows[i];

            for (var j = row.cells.length; j < cols; j++) {
                var cell = row.insertCell(-1);
            }
        }
    };

    elt2.firstChild.innerHTML = '';
    var picker = createPicker(5, 5);
    elt2.firstChild.appendChild(picker);

    var label = document.createElement('div');
    label.style.padding = '4px';
    label.style.fontSize = Menus.prototype.defaultFontSize + 'px';
    label.innerHTML = '1x1';
    elt2.firstChild.appendChild(label);

    function mouseover(e) {
        td = graph.getParentByName(mxEvent.getSource(e), 'TD');
        var selected = false;

        if (td != null) {
            row2 = graph.getParentByName(td, 'TR');
            var ext = (mxEvent.isMouseEvent(e)) ? 2 : 4;
            extendPicker(picker, Math.min(20, row2.sectionRowIndex + ext), Math.min(20, td.cellIndex + ext));
            label.innerHTML = (td.cellIndex + 1) + 'x' + (row2.sectionRowIndex + 1);

            for (var i = 0; i < picker.rows.length; i++) {
                var r = picker.rows[i];

                for (var j = 0; j < r.cells.length; j++) {
                    var cell = r.cells[j];

                    if (i == row2.sectionRowIndex &&
                        j == td.cellIndex) {
                        selected = cell.style.backgroundColor == 'blue';
                    }

                    if (i <= row2.sectionRowIndex && j <= td.cellIndex) {
                        cell.style.backgroundColor = 'blue';
                    } else {
                        cell.style.backgroundColor = 'transparent';
                    }
                }
            }
        }

        mxEvent.consume(e);

        return selected;
    };

    mxEvent.addGestureListeners(picker, null, null, mxUtils.bind(this, function (e) {
        var selected = mouseover(e);

        if (td != null && row2 != null && selected) {
            insertFn(e, row2.sectionRowIndex + 1, td.cellIndex + 1);

            // 需要异步处理以阻止菜单下元素的鼠标事件
            window.setTimeout(mxUtils.bind(this, function () {
                this.editorUi.hideCurrentMenu();
            }), 0);
        }
    }));
    mxEvent.addListener(picker, 'mouseover', mouseover);
};

/**
 * 为指定的菜单添加边样式改变项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {string} label - 菜单项的显示标签
 * @param {Array} keys - 要改变的样式属性键数组
 * @param {Array} values - 对应的样式属性值数组
 * @param {string} sprite - 菜单项的图标样式类名
 * @param {HTMLElement} parent - 父菜单容器元素
 * @param {boolean} reset - 是否重置边上的所有控制点
 * @returns {HTMLElement} 返回创建的菜单项元素
 */
Menus.prototype.edgeStyleChange = function (menu, label, keys, values, sprite, parent, reset) {
    return menu.addItem(label, null, mxUtils.bind(this, function () {
        // 获取图形编辑器实例
        var graph = this.editorUi.editor.graph;
        // 停止当前编辑状态
        graph.stopEditing(false);

        // 开始图形模型更新事务
        graph.getModel().beginUpdate();
        try {
            // 获取所有选中的单元格
            var cells = graph.getSelectionCells();
            var edges = [];

            // 遍历所有选中单元格，处理边元素
            for (var i = 0; i < cells.length; i++) {
                var cell = cells[i];

                // 只处理边类型的单元格
                if (graph.getModel().isEdge(cell)) {
                    // 如果需要重置，则清除所有边控制点
                    if (reset) {
                        var geo = graph.getCellGeometry(cell);

                        // 重置所有边控制点
                        if (geo != null) {
                            geo = geo.clone();
                            geo.points = null;
                            graph.getModel().setGeometry(cell, geo);
                        }
                    }

                    // 应用样式改变
                    for (var j = 0; j < keys.length; j++) {
                        graph.setCellStyles(keys[j], values[j], [cell]);
                    }

                    // 将处理过的边添加到结果数组
                    edges.push(cell);
                }
            }

            // 触发样式改变事件
            this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', keys,
                'values', values, 'cells', edges));
        } finally {
            // 结束图形模型更新事务
            graph.getModel().endUpdate();
        }
    }), parent, sprite);
};

/**
 * 为指定的菜单添加样式改变项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {string} label - 菜单项的显示标签
 * @param {Array} keys - 要改变的样式属性键数组
 * @param {Array} values - 对应的样式属性值数组
 * @param {string} sprite - 菜单项的图标样式类名
 * @param {HTMLElement} parent - 父菜单容器元素
 * @param {Function} fn - 内容编辑模式下的自定义处理函数
 * @param {Function} post - 样式应用后的回调函数
 * @returns {HTMLElement} 返回创建的菜单项元素
 */
Menus.prototype.styleChange = function (menu, label, keys, values, sprite, parent, fn, post) {
    // 创建样式改变应用函数
    var apply = this.createStyleChangeFunction(keys, values);

    return menu.addItem(label, null, mxUtils.bind(this, function () {
        var graph = this.editorUi.editor.graph;

        // 如果在内容编辑模式且提供了自定义函数，则执行自定义函数
        if (fn != null && graph.cellEditor.isContentEditing()) {
            fn();
        } else {
            // 否则应用标准的样式改变
            apply(post);
        }
    }), parent, sprite);
};

/**
 * 创建样式改变应用函数，用于批量应用样式更改到选中的单元格。
 * @param {Array} keys - 要改变的样式属性键数组
 * @param {Array} values - 对应的样式属性值数组
 * @returns {Function} 返回样式应用函数，接受一个可选的post回调参数
 */
Menus.prototype.createStyleChangeFunction = function (keys, values) {
    return mxUtils.bind(this, function (post) {
        // 获取图形编辑器实例
        var graph = this.editorUi.editor.graph;
        // 停止当前编辑状态
        graph.stopEditing(false);

        // 开始图形模型更新事务
        graph.getModel().beginUpdate();
        try {
            // 获取所有选中的单元格
            var cells = graph.getSelectionCells();

            // 遍历所有样式键值对并应用更改
            for (var i = 0; i < keys.length; i++) {
                graph.setCellStyles(keys[i], values[i], cells);

                // 移除CSS对齐属性以产生一致的输出
                if (keys[i] == mxConstants.STYLE_ALIGN) {
                    graph.updateLabelElements(cells, function (elt) {
                        elt.removeAttribute('align');
                        elt.style.textAlign = null;
                    });
                }

                // 字体更改后更新自动调整大小
                if (keys[i] == mxConstants.STYLE_FONTFAMILY) {
                    for (var j = 0; j < cells.length; j++) {
                        if (graph.model.getChildCount(cells[j]) == 0) {
                            graph.autoSizeCell(cells[j], false);
                        }
                    }
                }
            }

            // 如果提供了后处理回调，则执行
            if (post != null) {
                post();
            }

            // 触发样式改变事件
            this.editorUi.fireEvent(new mxEventObject('styleChanged',
                'keys', keys, 'values', values, 'cells', cells));
        } finally {
            // 结束图形模型更新事务
            graph.getModel().endUpdate();
        }
    });
};

/**
 * 为指定的菜单添加带提示的样式改变项，会弹出对话框让用户输入新值。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {string} label - 菜单项的显示标签
 * @param {string} hint - 输入提示文本
 * @param {string} defaultValue - 默认值
 * @param {string} key - 要改变的样式属性键
 * @param {HTMLElement} parent - 父菜单容器元素
 * @param {boolean} enabled - 菜单项是否启用
 * @param {Function} fn - 值改变后的回调函数
 * @param {string} sprite - 菜单项的图标样式类名
 * @returns {HTMLElement} 返回创建的菜单项元素
 */
Menus.prototype.promptChange = function (menu, label, hint, defaultValue, key, parent, enabled, fn, sprite) {
    return menu.addItem(label, null, mxUtils.bind(this, function () {
        // 获取图形编辑器实例
        var graph = this.editorUi.editor.graph;
        // 获取当前选中单元格的样式值作为默认值
        var value = defaultValue;
        var state = graph.getView().getState(graph.getSelectionCell());

        // 如果选中单元格有对应的样式值，则使用该值
        if (state != null) {
            value = state.style[key] || value;
        }

        // 创建文件名对话框用于输入新值
        var dlg = new FilenameDialog(this.editorUi, value, mxResources.get('apply'), mxUtils.bind(this, function (newValue) {
            // 如果输入了有效的新值，则应用样式更改
            if (newValue != null && newValue.length > 0) {
                graph.getModel().beginUpdate();
                try {
                    graph.stopEditing(false);
                    graph.setCellStyles(key, newValue);
                } finally {
                    graph.getModel().endUpdate();
                }

                // 如果提供了回调函数，则执行
                if (fn != null) {
                    fn(newValue);
                }
            }
        }), mxResources.get('enterValue') + ((hint.length > 0) ? (' ' + hint) : ''));
        // 显示对话框
        this.editorUi.showDialog(dlg.container, 300, 80, true, true);
        dlg.init();
    }), parent, sprite, enabled);
};

/**
 * 添加颜色选择器的处理程序，用于在指定元素中显示颜色选择菜单。
 * @param {string} key - 样式属性键名
 * @param {string} cmd - 文档命令，用于内容编辑模式
 * @param {string} defaultValue - 默认颜色值
 */
Menus.prototype.pickColor = function (key, cmd, defaultValue) {
    var graph = this.editorUi.editor.graph;
    var h = 226 + ((Math.ceil(ColorDialog.prototype.presetColors.length / 12) +
        Math.ceil(ColorDialog.prototype.defaultColors.length / 12)) * 17);

    if (cmd != null && graph.cellEditor.isContentEditing()) {
        // 为内置编辑器保存和恢复文本选择状态
        var selState = graph.cellEditor.saveSelection();

        var dlg = new ColorDialog(this.editorUi, defaultValue || '000000', mxUtils.bind(this, function (color) {
            graph.cellEditor.restoreSelection(selState);
            document.execCommand(cmd, false, (color != mxConstants.NONE) ? color : 'transparent');
        }), function () {
            graph.cellEditor.restoreSelection(selState);
        });
        this.editorUi.showDialog(dlg.container, 230, h, true, true);
        dlg.init();
    } else {
        if (this.colorDialog == null) {
            this.colorDialog = new ColorDialog(this.editorUi);
        }

        this.colorDialog.currentColorKey = key;
        var state = graph.getView().getState(graph.getSelectionCell());
        var color = 'none';

        if (state != null) {
            color = state.style[key] || color;
        }

        if (color == 'none') {
            color = 'ffffff';
            this.colorDialog.picker.fromString('ffffff');
            this.colorDialog.colorInput.value = 'none';
        } else {
            this.colorDialog.picker.fromString(color);
        }

        this.editorUi.showDialog(this.colorDialog.container, 230, h, true, true);
        this.colorDialog.init();
    }
};

/**
 * 切换指定样式的开关状态。
 * @param {string} key - 要切换的样式属性键名
 * @param {string} defaultValue - 默认样式值
 */
Menus.prototype.toggleStyle = function (key, defaultValue) {
    var graph = this.editorUi.editor.graph;
    var value = graph.toggleCellStyles(key, defaultValue);
    this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', [key], 'values', [value],
        'cells', graph.getSelectionCells()));
};

/**
 * 为指定的菜单添加菜单项，支持快捷键显示和选中状态指示。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {string} key - 菜单项对应的动作键名
 * @param {HTMLElement} parent - 父菜单容器元素
 * @param {Object} trigger - 触发对象，用于传递给动作函数
 * @param {string} sprite - 菜单项的图标样式类名
 * @param {string} label - 菜单项的显示标签，如果未提供则使用动作的默认标签
 * @returns {HTMLElement} 返回创建的菜单项元素，如果动作不存在或不可见则返回null
 */
Menus.prototype.addMenuItem = function (menu, key, parent, trigger, sprite, label) {
    // 获取对应的动作对象
    var action = this.editorUi.actions.get(key);

    // 检查动作是否存在、是否启用且可见
    if (action != null && (menu.showDisabled || action.isEnabled()) && action.visible) {
        // 创建菜单项
        var item = menu.addItem(label || action.label, null, function (evt) {
            action.funct(trigger, evt);
        }, parent, sprite, action.isEnabled());

        // 为切换动作添加选中标记
        if (action.toggleAction && action.isSelected()) {
            menu.addCheckmark(item, Editor.checkmarkImage);
        }

        // 添加快捷键显示
        this.addShortcut(item, action);

        return item;
    }

    return null;
};

/**
 * 为指定的菜单项添加快捷键显示。
 * @param {HTMLElement} item - 要添加快捷键显示的菜单项元素
 * @param {Object} action - 包含快捷键信息的动作对象
 */
Menus.prototype.addShortcut = function (item, action) {
    // 如果动作定义了快捷键，则显示在菜单项中
    if (action.shortcut != null) {
        // 获取菜单项的最后一个单元格用于显示快捷键
        var td = item.firstChild.nextSibling.nextSibling;
        // 创建快捷键显示元素
        var span = document.createElement('span');
        span.style.color = 'gray';
        mxUtils.write(span, action.shortcut);
        td.appendChild(span);
    }
};

/**
 * 批量为指定的菜单添加多个菜单项，支持分隔符和自定义标签。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {Array} keys - 菜单项键名数组，'-'表示分隔符
 * @param {HTMLElement} parent - 父菜单容器元素
 * @param {Object} trigger - 触发对象，用于传递给动作函数
 * @param {Array} sprites - 可选的图标样式类名数组
 * @param {Array} labels - 可选的自定义标签数组
 */
Menus.prototype.addMenuItems = function (menu, keys, parent, trigger, sprites, labels) {
    // 遍历所有键名，为每个键创建对应的菜单项
    for (var i = 0; i < keys.length; i++) {
        if (keys[i] == '-') {
            // 如果键名为'-'，则添加分隔符
            menu.addSeparator(parent);
        } else {
            // 否则添加对应的菜单项
            this.addMenuItem(menu, keys[i], parent, trigger, (sprites != null) ? sprites[i] : null, (labels != null) ? labels[i] : null);
        }
    }
};

/**
 * 为当前图形和历史记录创建键盘事件处理程序。
 * @param {Menu} menu - 要配置的弹出菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.createPopupMenu = function (menu, cell, evt) {

    menu.smartSeparators = true;

    if (!isFzPage) {
        // 动态显示右键菜单
        this.addObjectOldMenus(menu, cell, evt);
    }

    // this.addPopupMenuHistoryItems(menu, cell, evt);
    // this.addPopupMenuEditItems(menu, cell, evt);
    // this.addPopupMenuStyleItems(menu, cell, evt);
    // this.addPopupMenuArrangeItems(menu, cell, evt);
    // this.addPopupMenuCellItems(menu, cell, evt);
    // this.addPopupMenuSelectionItems(menu, cell, evt);

};

/**
 * 异步添加对象的旧菜单项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.addObjectOldMenus = async function (menu, cell, evt) {


    console.log("addObjectOldMenus");
    var graph = this.editorUi.editor.graph;
    menu.smartSeparators = true;
    cell = graph.getSelectionCell();
    var state = graph.view.getState(cell);

    if (window.isGuideModel) return

    if (graph.isSelectionEmpty()) {
        this.addMenuItems(menu, ['undo', 'redo', '-', 'pasteHere'], null, evt);
    } else {
        // 单选引用对象
        if (graph.singleSelectQuote()) {
            this.addMenuItems(menu, ['showQuoteData'], null, evt);
        } else if (graph.getSelectionCount() == 1 && graph.getSelectionCell().isEntity()) { // 单选非引用对象
            this.addMenuItems(menu, ['-', 'editData'], null, evt);
        }

        if (graph.getSelectionCell().value instanceof Object) {
            this.addMenuItem(menu, 'setDefaultStyle', null, evt)
        }

        if (cell.value && cell.value instanceof Object && cell.value.tagName !== 'relation' &&
            graph.getModel().isVertex(cell) && mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE, null) != null) {
            // 如果样式中有图片，则显示编辑图片操作
            menu.addSeparator();
            // 暂时屏蔽编辑图片
            this.addMenuItem(menu, 'image', null, evt, null, mxResources.get('editImage') + '...', );
        }
        //关系线增加菜单跳转到交互清单
        /** 只有航天1院需要此惨菜单
          if (cell.value && cell.value instanceof Object && cell.value.tagName === 'relation'){
              let param = {
                  data:[{
                      eObjectId:cell.value.getAttribute('metaId'),
                      objectId:cell.value.getAttribute('objectId')
                  }],
                  frameworkCode:window.parent.top.getProjectStore(window.parent.top.$constants.FRAMEWORK_CODE),
                  taskId:window.parent.top.getProjectStore(window.parent.top.$constants.TASK_ID)
              }
              let {data} = await window.$axios.post(`${window.parent.top.g.ApiUrl2}/sysmlDefineNode/getRelationJumpZBTableInfo`,param)
              if(Object.keys(data).length){
                  this.addMenuItem(menu, 'viewTable', null, {...data,objectId:cell.value.getAttribute('objectId')});
              }
          }
         */
        // 创建状态图
        if (graph.getSelectionCount() == 1 && (cell.value instanceof Object && cell.value.attributes.addStateDiagram != null && cell.value.attributes.addStateDiagram.value == "true" && cell.getValue().getAttribute("objectId") != '')) {
            this.addMenuItems(menu, ['createStatus'], null, evt);
        }

        if (graph.getSelectionCount() == 1 && typeof (graph.getSelectionCell().value) == 'object' && (cell.value.attributes.addChildPageFlag != null && cell.value.attributes.addChildPageFlag.value == "true")) {
            this.addMenuItems(menu, ['addChildPage'], null, evt);
        }
        if (graph.getSelectionCount() == 1 && typeof (graph.getSelectionCell().value) == 'object' && graph.getSelectionCell().value) {
            if (Array.isArray(window.sysmlConfiguration.addSysmlModelList) && window.sysmlConfiguration.addSysmlModelList.includes(cell.value.getAttribute('metaId'))) {
                var addSysmlDiagram = menu.addItem('创建图表', null, null);
                await window.$axios.post(`${window.parent.top.g.ApiUrl2}/sysmlDefineNode/getSYSMLModelTypes?type=model_object&metaId=${cell.value.getAttribute('metaId')}`).then((res) => {
                    let typeList = (res.data || []);
                    if (typeList != null && typeList.length > 0) {
                        for (var i = 0; i < typeList.length; i++) {
                            var currentObj = new Object();
                            currentObj.item = typeList[i];
                            let key = ''
                            if (currentObj.item.name === '创建绘图') {
                                key = 'addSysmlDrawingDiagram'
                            } else if (currentObj.item.name === '创建对象') {
                                key = 'addSysmlDataDiagram'
                            }
                            const addSysmlTypeDiagram = this.addMenuItem(menu, 'addSysmlDiagram', addSysmlDiagram, {}, null, '' + typeList[i].name);
                            (currentObj.item.children || []).forEach(item => {
                                item.typeList = currentObj.item.children;
                                this.addMenuItem(menu, key, addSysmlTypeDiagram, {
                                    ...item,
                                    metaId: cell.value.getAttribute('metaId'),
                                    relateId: cell.value.getAttribute('objectId') || cell.value.getAttribute('quoteId')
                                }, null, item.name);
                            })
                        }
                    }
                })
            }
        }

        if (graph.getSelectionCount() == 1 && typeof (graph.getSelectionCell().value) == 'object' && graph.getSelectionCell().value) {
            if (graph.getSelectionCell().value.nodeName !== 'quote') {
                if (cell.value.getAttribute('display') === 'LABEL_ER_ENTITY') {
                    this.addMenuItems(menu, ['-', 'addAttr'], null, evt); //增加属性
                } else if (cell.value.getAttribute('display') === 'LABEL_ER_ATTRIBUTE') {
                    console.log(cell.isMajor);
                    if (cell.isMajor === 2 && !cell.isInherit) { //为外键时
                        this.addMenuItems(menu, ['-', 'becomeMajorKey'], null, evt); //设为主键
                    } else if (cell.isMajor === 1 && !cell.isInherit) {
                        this.addMenuItems(menu, ['-', 'cancelMajorKey'], null, evt); //取消主键
                    }
                } else if (cell.value.getAttribute('display') === 'UML_SHEJILEI' || cell.value.getAttribute('display') === 'UML_INTERFACE') {
                    this.addMenuItems(menu, ['-', 'leishuxin'], null, evt);
                } else {
                    if (typeof (cell.getValue()) === 'object' && cell.value.getAttribute('business') === 'BUSINESS_TREENODE' || cell.value.getAttribute('business') === 'BUSINESS_NORMAL') {
                        // var toggleFigureType = menu.addItem('切换图形', null, null)
                        // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType, 'Rectangle', null, '矩形');
                        // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType, 'ellipse', null, '椭圆');
                        // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType, 'triangle;whiteSpace=wrap', null, '三角形');
                        // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType, 'shape=parallelogram;whiteSpace=wrap', null, '四边形');
                        // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType, 'rhombus;whiteSpace=wrap', null, '菱形');
                        // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType, 'shape=hexagon;perimeter=hexagonPerimeter;whiteSpace=wrap', null, '六边形');
                        // this.addMenuItems(menu, ['-', 'addChildPage', 'addChildNode', 'addFileBase', 'editData'], null, evt);
                        // this.addMenuItems(menu, ['-',  'addFileBase'], null, evt);
                    } else if (cell.getValue().getAttribute('defineId')) {
                        //关联资源属性 editRsRel
                        // this.addMenuItems(menu, ['-', 'addFileBase','editRsRel'], null, evt);
                    } else {
                        // this.addMenuItems(menu, ['-', 'addFileBase'], null, evt);
                    }
                }
                if (cell.value && cell.value instanceof Object && cell.value.tagName !== 'relation' &&
                    graph.getModel().isVertex(cell) && mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE, null) != null) {
                    this.addMenuItems(menu, ['-', 'insertLocalImage'], null, evt); //插入本地图片

                }
            }
            // addChildNodeConfig key是当前模型内可以创建子节点的对象的metaId,value是创建子节点的默认连线的metaID
            if (cell.value instanceof Object && addChildNodeConfig.hasOwnProperty(cell.value.getAttribute('metaId'))) {
                this.addMenuItems(menu, ['-', 'addChildNode'], null, evt);
            }
        }

        this.addMenuItems(menu, ['delete'], null, evt);

        // 通用元素没有从模型中删除
        if (typeof (cell.value) == 'object' && cell.value != null) {
            this.addMenuItems(menu, ['deleteFromModel'], null, evt);
        }

        this.addMenuItems(menu, ['selectSameTypeCell', '-'], null, evt);
        if (graph.isCopyable(graph.getSelectionCells())) {
            this.addMenuItems(menu, ['copy', '-'], null, evt);
        }

        if (graph.singleSelectQuote()) {
            this.addMenuItems(menu, ['toggleQuote'], null, evt);
        }

        if (typeof (cell.value) == 'object' && cell.value != null && cell.value.nodeName == 'relaentity' && (cell.value.attributes.newType != null && cell.value.attributes.newType.value == "quote")) {
            this.addMenuItems(menu, ['toggleQuote'], null, evt);
        }

        if (graph.hasSelectVertex() && graph.getSelectionCell().getStyle().indexOf('swimlane') < 0 && !graph.hasSelectQuote()) {
            // var toggleFigureType=menu.addItem('切换图形',null,null);
            // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType,'Rectangle',null,'矩形');
            // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType,'ellipse',null,'椭圆');
            // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType,'triangle;whiteSpace=wrap',null,'三角形');
            // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType,'shape=parallelogram;whiteSpace=wrap',null,'四边形');
            // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType,'rhombus;whiteSpace=wrap',null,'菱形');
            // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType,'shape=hexagon;perimeter=hexagonPerimeter;whiteSpace=wrap',null,'六边形');
            // this.addMenuItem(menu, 'toggleFigureType', toggleFigureType,'ellipse;shape=cloud;whiteSpace=wrap',null,'云');
        }

    }

    if (graph.getSelectionCount() > 0) {
        if (graph.getSelectionCount() == 1 && typeof (graph.getSelectionCell().value) == 'object') {
            // this.addMenuItems(menu, ['setAsDefaultStyle'], null, evt);
        }

        menu.addSeparator();

        cell = graph.getSelectionCell();
        var state = graph.view.getState(cell);

        if (state != null) {
            if (graph.getSelectionCount() == 1) {
                this.addMenuItems(menu, ['toFront', 'toBack', '-'], null, evt);
            }

            if (graph.getModel().isEdge(cell) && mxUtils.getValue(state.style, mxConstants.STYLE_EDGE, null) != 'entityRelationEdgeStyle' &&
                mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) != 'arrow') {
                var handler = graph.selectionCellsHandler.getHandler(cell);
                var isWaypoint = false;

                if (handler instanceof mxEdgeHandler && handler.bends != null && handler.bends.length > 2) {
                    var index = handler.getHandleForEvent(graph.updateMouseEvent(new mxMouseEvent(evt)));

                    // 在执行前配置移除路径点动作
                    // 使用触发器参数会更简洁，但无论如何都必须在这里找到路径点
                    var rmWaypointAction = this.editorUi.actions.get('removeWaypoint');
                    rmWaypointAction.handler = handler;
                    rmWaypointAction.index = index;

                    isWaypoint = index > 0 && index < handler.bends.length - 1;
                }

                this.addMenuItems(menu, ['-', (isWaypoint) ? 'removeWaypoint' : 'addWaypoint'], null, evt);

                // 如果存在路径点，则添加重置路径点选项
                var geo = graph.getModel().getGeometry(cell);

                if (geo != null && geo.points != null && geo.points.length > 0) {
                    this.addMenuItems(menu, ['clearWaypoints'], null, evt);
                }
            }

            if (graph.getSelectionCount() > 1) {
                menu.addSeparator();
                this.addMenuItems(menu, ['group'], null, evt);
            } else if (graph.getSelectionCount() == 1 && !graph.getModel().isEdge(cell) && !graph.isSwimlane(cell) &&
                graph.getModel().getChildCount(cell) > 0) {
                menu.addSeparator();
                this.addMenuItems(menu, ['ungroup'], null, evt);
            }

        }
    } else {
        this.addMenuItems(menu, ['-', 'selectVertices', 'selectEdges', '-', 'selectAll'], null, evt);
    }

    //对象是否是实例 或者 是需求获取架构数据

    if (await findCellObjectIsClass(cell)) {
        menu.addSeparator();
    }
    if (null != cell && cell instanceof Object) {
        var className = cell.getAttribute('className')
        if (className && className === '资源') {
            this.addMenuItems(menu, ['selectResourceVersion'], null, evt);
        }
    }

    // 异步加载完成菜单后重新定位
    menu.div && mxUtils.fit(menu.div);
    // 添加子图右键菜单
    const drawioBus = window.top.$store.state.bus.drawioBus
    drawioBus.$emit('addChildGraphMenu', {
        menu: menu,
        cell: cell,
        evt,
        evt
    });
    // if(cell){}
    // this.addMenuItems(menu, ['-', 'child-graph'], null ,evt);
}


/**
 * 为弹出菜单添加历史记录相关项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.addPopupMenuHistoryItems = function (menu, cell, evt) {
    if (this.editorUi.editor.graph.isSelectionEmpty()) {
        this.addMenuItems(menu, ['undo', 'redo'], null, evt);
    }
};

/**
 * 为弹出菜单添加编辑相关项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.addPopupMenuEditItems = function (menu, cell, evt) {
    if (this.editorUi.editor.graph.isSelectionEmpty()) {
        this.addMenuItems(menu, ['pasteHere'], null, evt);
    } else {
        this.addMenuItems(menu, ['delete', 'deleteFromModel', '-', 'cut', 'copy', '-', 'duplicate'], null, evt);
    }
};

/**
 * 为弹出菜单添加样式相关项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.addPopupMenuStyleItems = function (menu, cell, evt) {
    if (this.editorUi.editor.graph.getSelectionCount() == 1) {
        this.addMenuItems(menu, ['-', 'setAsDefaultStyle'], null, evt);
    } else if (this.editorUi.editor.graph.isSelectionEmpty()) {
        this.addMenuItems(menu, ['-', 'clearDefaultStyle'], null, evt);
    }
};

/**
 * 为弹出菜单添加排列相关项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.addPopupMenuArrangeItems = function (menu, cell, evt) {
    var graph = this.editorUi.editor.graph;

    if (!graph.isSelectionEmpty()) {
        this.addMenuItems(menu, ['-', 'toFront', 'toBack'], null, evt);
    }

    if (graph.getSelectionCount() > 1) {
        this.addMenuItems(menu, ['-', 'group'], null, evt);
    } else if (graph.getSelectionCount() == 1 && !graph.getModel().isEdge(cell) &&
        !graph.isSwimlane(cell) && graph.getModel().getChildCount(cell) > 0) {
        this.addMenuItems(menu, ['-', 'ungroup'], null, evt);
    }
};

/**
 * 为弹出菜单添加单元格相关项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.addPopupMenuCellItems = function (menu, cell, evt) {
    var graph = this.editorUi.editor.graph;
    cell = graph.getSelectionCell();
    var state = graph.view.getState(cell);
    menu.addSeparator();

    if (state != null) {
        var hasWaypoints = false;

        if (graph.getModel().isEdge(cell) && mxUtils.getValue(state.style, mxConstants.STYLE_EDGE, null) != 'entityRelationEdgeStyle' &&
            mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) != 'arrow') {
            var handler = graph.selectionCellsHandler.getHandler(cell);
            var isWaypoint = false;

            if (handler instanceof mxEdgeHandler && handler.bends != null && handler.bends.length > 2) {
                var index = handler.getHandleForEvent(graph.updateMouseEvent(new mxMouseEvent(evt)));

                // 在执行前配置移除路径点动作
                // 使用触发器参数会更简洁，但无论如何都必须在这里找到路径点
                var rmWaypointAction = this.editorUi.actions.get('removeWaypoint');
                rmWaypointAction.handler = handler;
                rmWaypointAction.index = index;

                isWaypoint = index > 0 && index < handler.bends.length - 1;
            }

            menu.addSeparator();
            this.addMenuItem(menu, 'turn', null, evt, null, mxResources.get('reverse'));
            this.addMenuItems(menu, [(isWaypoint) ? 'removeWaypoint' : 'addWaypoint'], null, evt);

            // 如果存在路径点，则添加重置路径点选项
            var geo = graph.getModel().getGeometry(cell);
            hasWaypoints = geo != null && geo.points != null && geo.points.length > 0;
        }

        if (graph.getSelectionCount() == 1 && (hasWaypoints || (graph.getModel().isVertex(cell) &&
                graph.getModel().getEdgeCount(cell) > 0))) {
            this.addMenuItems(menu, ['-', 'clearWaypoints'], null, evt);
        }

        if (graph.getSelectionCount() == 1) {
            this.addMenuItems(menu, ['-', 'editStyle', 'editData', 'editLink'], null, evt);

            // 如果样式中有图片，则显示编辑图片操作
            if (graph.getModel().isVertex(cell) && mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE, null) != null) {
                menu.addSeparator();
                this.addMenuItem(menu, 'image', null, evt).firstChild.nextSibling.innerHTML = mxResources.get('editImage') + '...';
            }
        }
    }
};

/**
 * 为弹出菜单添加选择相关项。
 * @param {Menu} menu - 要添加菜单项的目标菜单
 * @param {mxCell} cell - 相关的单元格对象
 * @param {Event} evt - 触发事件
 */
Menus.prototype.addPopupMenuSelectionItems = function (menu, cell, evt) {
    if (this.editorUi.editor.graph.isSelectionEmpty()) {
        this.addMenuItems(menu, ['-', 'selectVertices', 'selectEdges', 'selectAll'], null, evt);
    }
};

/**
 * 为指定的容器创建菜单栏。
 * @param {HTMLElement} container - 菜单栏的DOM容器元素
 * @returns {Menubar} 返回创建的菜单栏实例
 */
Menus.prototype.createMenubar = function (container) {
    var menubar = new Menubar(this.editorUi, container);
    var menus = this.defaultMenuItems;

    for (var i = 0; i < menus.length; i++) {
        (mxUtils.bind(this, function (menu) {
            var elt = menubar.addMenu(mxResources.get(menus[i]), mxUtils.bind(this, function () {
                // 允许扩展menu.funct功能
                menu.funct.apply(this, arguments);
            }));

            this.menuCreated(menu, elt);
        }))(this.get(menus[i]));
    }

    return menubar;
};

/**
 * 当菜单被创建时调用的回调函数。
 * @param {Menu} menu - 被创建的菜单对象
 * @param {HTMLElement} elt - 菜单对应的DOM元素
 * @param {string} className - 可选的CSS类名，默认为'geItem'
 */
Menus.prototype.menuCreated = function (menu, elt, className) {
    if (elt != null) {
        className = (className != null) ? className : 'geItem';

        menu.addListener('stateChanged', function () {
            elt.enabled = menu.enabled;

            if (!menu.enabled) {
                elt.className = className + ' mxDisabled';

                if (document.documentMode == 8) {
                    elt.style.color = '#c3c3c3';
                }
            } else {
                elt.className = className;

                if (document.documentMode == 8) {
                    elt.style.color = '';
                }
            }
        });
    }
};

/**
 * 为指定的编辑器UI构造一个新的菜单栏。
 * @param {Object} editorUi - 菜单栏所属的编辑器UI实例
 * @param {HTMLElement} container - 菜单栏的DOM容器元素
 */
function Menubar(editorUi, container) {
    // 存储编辑器UI实例的引用
    this.editorUi = editorUi;
    // 存储菜单栏的DOM容器元素
    this.container = container;
};

/**
 * 隐藏当前显示的菜单。
 */
Menubar.prototype.hideMenu = function () {
    this.editorUi.hideCurrentMenu();
};

/**
 * 向菜单栏添加一个子菜单。
 * @param {string} label - 菜单项的显示标签
 * @param {Function} funct - 点击菜单项时执行的函数
 * @param {HTMLElement} before - 可选的插入位置，在此元素之前插入新菜单项
 * @returns {HTMLElement} 返回创建的菜单项元素
 */
Menubar.prototype.addMenu = function (label, funct, before) {
    // 创建菜单项的锚元素
    var elt = document.createElement('a');
    elt.className = 'geItem';
    mxUtils.write(elt, label);
    // 添加菜单处理程序
    this.addMenuHandler(elt, funct);

    // 根据before参数决定插入位置
    if (before != null) {
        this.container.insertBefore(elt, before);
    } else {
        this.container.appendChild(elt);
    }

    return elt;
};

/**
 * 为指定的元素添加显示菜单的处理程序。
 * @param {HTMLElement} elt - 要添加处理程序的DOM元素
 * @param {Function} funct - 点击元素时执行的菜单显示函数
 */
Menubar.prototype.addMenuHandler = function (elt, funct) {
    if (funct != null) {
        var show = true;

        var clickHandler = mxUtils.bind(this, function (evt) {
            if (show && elt.enabled == null || elt.enabled) {
                this.editorUi.editor.graph.popupMenuHandler.hideMenu();
                var menu = new mxPopupMenu(funct);
                menu.div.className += ' geMenubarMenu';
                menu.smartSeparators = true;
                menu.showDisabled = true;
                menu.autoExpand = true;

                // 隐藏时禁用自动展开并销毁菜单
                menu.hideMenu = mxUtils.bind(this, function () {
                    mxPopupMenu.prototype.hideMenu.apply(menu, arguments);
                    this.editorUi.resetCurrentMenu();
                    menu.destroy();
                });

                var offset = mxUtils.getOffset(elt);
                menu.popup(offset.x, offset.y + elt.offsetHeight, null, evt);
                this.editorUi.setCurrentMenu(menu, elt);
            }

            mxEvent.consume(evt);
        });

        // 在展开状态下自动显示菜单
        mxEvent.addListener(elt, 'mousemove', mxUtils.bind(this, function (evt) {
            if (this.editorUi.currentMenu != null && this.editorUi.currentMenuElt != elt) {
                this.editorUi.hideCurrentMenu();
                clickHandler(evt);
            }
        }));

        // 如果菜单已在显示则隐藏，并阻止焦点获取
        mxEvent.addListener(elt, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown',
            mxUtils.bind(this, function (evt) {
                show = this.currentElt != elt;
                evt.preventDefault();
            }));

        mxEvent.addListener(elt, 'click', mxUtils.bind(this, function (evt) {
            clickHandler(evt);
            show = true;
        }));
    }
};

/**
 * 销毁菜单栏实例，清理相关资源。
 */
Menubar.prototype.destroy = function () {
    // 目前没有需要清理的资源
};

/**
 * 为给定的参数构造一个新的菜单对象。
 * @param {Function} funct - 菜单执行时调用的函数
 * @param {boolean} enabled - 菜单是否启用，默认为true
 */
function Menu(funct, enabled) {
    mxEventSource.call(this);
    // 存储菜单执行函数
    this.funct = funct;
    // 存储菜单启用状态
    this.enabled = (enabled != null) ? enabled : true;
};

// Menu类继承自mxEventSource
mxUtils.extend(Menu, mxEventSource);

/**
 * 获取菜单的启用状态。
 * @returns {boolean} 返回菜单是否启用的状态
 */
Menu.prototype.isEnabled = function () {
    return this.enabled;
};

/**
 * 设置菜单的启用状态，并触发状态改变事件。
 * @param {boolean} value - 新的启用状态
 */
Menu.prototype.setEnabled = function (value) {
    // 只有当状态真正改变时才触发事件
    if (this.enabled != value) {
        this.enabled = value;
        this.fireEvent(new mxEventObject('stateChanged'));
    }
};

/**
 * 执行菜单的功能函数。
 * @param {Menu} menu - 菜单对象本身
 * @param {HTMLElement} parent - 父菜单容器元素
 */
Menu.prototype.execute = function (menu, parent) {
    this.funct(menu, parent);
};

/**
 * 在编辑器UI中创建和安装菜单系统。
 * 该方法为编辑器UI实例化一个新的菜单管理器。
 * @returns {Menus} 返回新创建的菜单管理器实例
 */
EditorUi.prototype.createMenus = function () {
    return new Menus(this);
};